package com.dj.mingkong.common.util;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;

/**
 * LocalDateTime时间工具类
 *
 * @author zenglonghui
 * @date: 2022/8/19 14:10
 */
public class LocalDateTimeUtils {
    private LocalDateTimeUtils () {}
    public static String DATE_PATTERN = "yyyy/MM/dd";
    /**
     * 获取指定日期所属周的周一的日期
     *
     * @param localDate 指定日期
     * @return LocalDateTime
     */
    public static LocalDateTime getMondayForThisWeek(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.MIN).with(DayOfWeek.MONDAY);
    }

    /**
     * 获取当前日期所属周的周一的日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getMondayForThisWeek() {
        return getMondayForThisWeek(LocalDate.now());
    }

    /**
     * 获取指定日期所属周的周日的日期
     *
     * @param localDate 指定日期
     * @return LocalDateTime
     */
    public static LocalDateTime getSundayForThisWeek(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.MIN).with(DayOfWeek.SUNDAY);
    }

    /**
     * 获取当前日期所属周的周日的日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getSundayForThisWeek() {
        return getSundayForThisWeek(LocalDate.now());
    }

    /**
     * 获取指定日期所属周的下周一的日期
     *
     * @param localDate 指定日期
     * @return LocalDateTime
     */
    public static LocalDateTime getMondayForNextWeek(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.MIN).plusWeeks(1).with(DayOfWeek.MONDAY);
    }

    /**
     * 获取当前日期所属周的下周一的日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getMondayForNextWeek() {
        return getMondayForNextWeek(LocalDate.now());
    }

    /**
     * 获取当前时间自定义下几周的周一日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getMondayForPlusWeeks(long num) {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN).plusWeeks(num).with(DayOfWeek.MONDAY);
    }

    /**
     * 获取指定日期所属周的下周日的日期
     *
     * @param localDate 指定日期
     * @return LocalDateTime
     */
    public static LocalDateTime getSundayForNextWeek(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.MIN).plusWeeks(1).with(DayOfWeek.SUNDAY);
    }

    /**
     * 获取当前日期所属周的下周日的日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getSundayForNextWeek() {
        return getSundayForNextWeek(LocalDate.now());
    }

    /**
     * 获取当前时间自定义下几周的周日日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getSundayForPlusWeeks(long num) {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN).plusWeeks(num).with(DayOfWeek.SUNDAY);
    }

    /**
     * 获取指定日期所属周的上周一的日期
     *
     * @param localDate 指定日期
     * @return LocalDateTime
     */
    public static LocalDateTime getMondayForUpWeek(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.MIN).minusWeeks(1).with(DayOfWeek.MONDAY);
    }

    /**
     * 获取当前日期所属周的上周一的日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getMondayForUpWeek() {
        return getMondayForUpWeek(LocalDate.now());
    }

    /**
     * 获取当前时间自定义上几周的周一日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getMondayForMinusWeeks(long num) {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN).minusWeeks(num).with(DayOfWeek.MONDAY);
    }

    /**
     * 获取指定日期所属周的上周日的日期
     *
     * @param localDate 指定日期
     * @return LocalDateTime
     */
    public static LocalDateTime getSundayForUpWeek(LocalDate localDate) {
        return LocalDateTime.of(localDate, LocalTime.MIN).minusWeeks(1).with(DayOfWeek.SUNDAY);
    }

    /**
     * 获取当前日期所属周的上周日的日期
     *
     * @return LocalDateTime
     */
    public static LocalDateTime getSundayForUpWeek() {
        return getSundayForUpWeek(LocalDate.now());
    }

    /**
     * 获取当前时间自定义上几周的周日日期
     *
     * @param num 第几周
     * @return LocalDateTime
     */
    public static LocalDateTime getSundayForMinusWeeks(long num) {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN).minusWeeks(num).with(DayOfWeek.SUNDAY);
    }

    /**
     * 指定格式为"yyyy-MM-dd HH:mm:ss"的字符串时间转化为LocalDateTime类型
     *
     * @param dateStr 指定日期字符串
     * @return LocalDateTime
     */
    public static LocalDateTime parse(String dateStr) {
        return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public static LocalDateTime parse(String dateStr, String pattern) {
        return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * LocalDateTime类型转化为格式为"yyyy-MM-dd HH:mm:ss"的字符串时间类型
     *
     * @param localDateTime LocalDateTime
     * @return String
     */
    public static String format(LocalDateTime localDateTime) {
        return localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public static String format(LocalDateTime localDateTime, String pattern) {
        return localDateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * Date类型时间转化为LocalDateTime类型
     *
     * @param date Date类型时间
     * @return LocalDateTime
     */
    public static LocalDateTime getLocalDateTimeFromDate(Date date) {
        return date.toInstant().atOffset(ZoneOffset.of("+8")).toLocalDateTime();
    }

    /**
     * LocalDateTime类型转化为Date类型时间
     *
     * @param localDateTime LocalDateTime类型
     * @return Date
     */
    public static Date getDateFromLocalDateTime(LocalDateTime localDateTime) {
        return Date.from(localDateTime.toInstant(ZoneOffset.of("+8")));
    }

    /**
     * 获取指定时间的00:00:00
     *
     * @param localDateTime 指定时间
     * @return LocalDateTime
     */
    public static LocalDateTime getLocalDateTimeForBegin(LocalDateTime localDateTime) {
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MIN);
    }

    /**
     * 获取指定时间的23:59:59
     *
     * @param localDateTime 指定时间
     * @return LocalDateTime
     */
    public static LocalDateTime getLocalDateTimeForEnd(LocalDateTime localDateTime) {
        return LocalDateTime.of(localDateTime.toLocalDate(), LocalTime.MAX);
    }

    /**
     * 时间戳(毫秒)转化为LocalDateTime格式
     *
     * @param timestamp 时间戳(毫秒)
     * @return LocalDateTime
     */
    public static LocalDateTime getLocalDateTimeFromTimestamp(Long timestamp) {
        return LocalDateTime.ofEpochSecond(timestamp / 1000, 0, ZoneOffset.ofHours(8));
    }

    /**
     * LocalDateTime格式转化为时间戳(毫秒)
     *
     * @param localDateTime LocalDateTime
     * @return Long
     */
    public static Long getTimestampFromLocalDateTime(LocalDateTime localDateTime) {
        return localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
    }

    /**
     * 获取指定格式的当前时间
     *
     * @param pattern 指定格式
     * @return 指定格式的当前时间日期字符串
     */
    public static String formatNow(String pattern) {
        return format(LocalDateTime.now(), pattern);
    }

    public static String formatNow() {
        return format(LocalDateTime.now());
    }

    /**
     * 判断dateTime1是否早于dateTime2
     *
     * @param dateTime1 日期时间1
     * @param dateTime2 日期时间2
     * @return 判断结果
     */
    public static boolean isBefore(LocalDateTime dateTime1, LocalDateTime dateTime2) {
        return dateTime1.isBefore(dateTime2);
    }

    /**
     * 判断dateTime1与dateTime2是否是同一时间
     *
     * @param dateTime1 日期时间1
     * @param dateTime2 日期时间2
     * @return 判断结果
     */
    public static boolean isEqual(LocalDateTime dateTime1, LocalDateTime dateTime2) {
        return dateTime1.isEqual(dateTime2);
    }

    /**
     * 判断dateTime1是否晚于dateTime2
     *
     * @param dateTime1 日期时间1
     * @param dateTime2 日期时间2
     * @return 判断结果
     */
    public static boolean isAfter(LocalDateTime dateTime1, LocalDateTime dateTime2) {
        return dateTime1.isAfter(dateTime2);
    }

    /**
     * 获取指定日期的毫秒
     *
     * @param dateTime 日期时间
     * @return 毫秒
     */
    public static Long getMilliByTime(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    /**
     * 获取指定日期的秒
     *
     * @param dateTime 日期时间
     * @return 秒
     */
    public static Long getSecondsByTime(LocalDateTime dateTime) {
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
    }

    /**
     * 日期加上一个数，根据field不同加不同值
     *
     * @param dateTime 日期时间
     * @param number   数值
     * @param field    单位
     * @return 已添加数值后的日期时间
     */
    public static LocalDateTime plus(LocalDateTime dateTime, long number, ChronoUnit field) {
        return dateTime.plus(number, field);
    }

    /**
     * 日期减去一个数，根据field不同减不同值
     *
     * @param dateTime 日期时间
     * @param number   数值
     * @param field    单位
     * @return 已减少数值后的日期时间
     */
    public static LocalDateTime minus(LocalDateTime dateTime, long number, ChronoUnit field) {
        return dateTime.minus(number, field);
    }

    /**
     * 获取两个日期的差
     *
     * @param startDateTime 开始时间
     * @param endDateTime   结束时间
     * @param field         单位
     * @return 两个日期之间的差值
     */
    public static long between(LocalDateTime startDateTime, LocalDateTime endDateTime, ChronoUnit field) {
        Period period = Period.between(LocalDate.from(startDateTime), LocalDate.from(endDateTime));
        if (field == ChronoUnit.YEARS) {
            return period.getYears();
        }
        if (field == ChronoUnit.MONTHS) {
            return period.getYears() * 12L + period.getMonths();
        }
        return field.between(startDateTime, endDateTime);
    }

    /**
     * 今天开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime todayStartTime() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
    }

    /**
     * 今天结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime todayEndTime() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
    }

    /**
     * 昨天开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime yesterdayStartTime() {
        return LocalDateTime.of(LocalDate.now().minus(1L, ChronoUnit.DAYS), LocalTime.MIN);
    }

    /**
     * 昨天开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime yesterdayEndTime() {
        return LocalDateTime.of(LocalDate.now().minus(1L, ChronoUnit.DAYS), LocalTime.MAX);
    }

    /**
     * 最近7天开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime last7DaysStartTime() {
        return LocalDateTime.of(LocalDate.now().minus(6L, ChronoUnit.DAYS), LocalTime.MIN);
    }

    /**
     * 最近7天结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime last7DaysEndTime() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
    }

    /**
     * 最近30天开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime last30DaysStartTime() {
        return LocalDateTime.of(LocalDate.now().minus(29L, ChronoUnit.DAYS), LocalTime.MIN);
    }

    /**
     * 最近30天结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime last30DaysEndTime() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
    }

    /**
     * 最近一年开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime last1YearStartTime() {
        return LocalDateTime.of(LocalDate.now().minus(1L, ChronoUnit.YEARS).plus(1L, ChronoUnit.DAYS), LocalTime.MIN);
    }

    /**
     * 最近一年结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime last1YearEndTime() {
        return LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
    }

    /**
     * 本月开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime monthStartTime() {
        return LocalDateTime.of(LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN);
    }

    /**
     * 本月结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime monthEndTime() {
        return LocalDateTime.of(LocalDate.now().with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX);
    }

    /**
     * 本季度开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime quarterStartTime() {
        LocalDate now = LocalDate.now();
        Month month = Month.of(now.getMonth().firstMonthOfQuarter().getValue());
        return LocalDateTime.of(LocalDate.of(now.getYear(), month, 1), LocalTime.MIN);
    }

    /**
     * 本季度结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime quarterEndTime() {
        LocalDate now = LocalDate.now();
        Month month = Month.of(now.getMonth().firstMonthOfQuarter().getValue()).plus(2L);
        return LocalDateTime.of(LocalDate.of(now.getYear(), month, month.length(now.isLeapYear())), LocalTime.MAX);
    }

    /**
     * 本半年开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime halfYearStartTime() {
        LocalDate now = LocalDate.now();
        Month month = (now.getMonthValue() > 6) ? Month.JULY : Month.JANUARY;
        return LocalDateTime.of(LocalDate.of(now.getYear(), month, 1), LocalTime.MIN);
    }

    /**
     * 本半年结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime halfYearEndTime() {
        LocalDate now = LocalDate.now();
        Month month = (now.getMonthValue() > 6) ? Month.DECEMBER : Month.JUNE;
        return LocalDateTime.of(LocalDate.of(now.getYear(), month, month.length(now.isLeapYear())), LocalTime.MAX);
    }

    /**
     * 本年开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime yearStartTime() {
        return LocalDateTime.of(LocalDate.now().with(TemporalAdjusters.firstDayOfYear()), LocalTime.MIN);
    }

    /**
     * 本年结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime yearEndTime() {
        return LocalDateTime.of(LocalDate.now().with(TemporalAdjusters.lastDayOfYear()), LocalTime.MAX);
    }

    /**
     * 上月开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime lastMonthStartTime() {
        return LocalDateTime.of(LocalDate.now().minus(1L, ChronoUnit.MONTHS).with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN);
    }

    /**
     * 上月结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime lastMonthEndTime() {
        return LocalDateTime.of(LocalDate.now().minus(1L, ChronoUnit.MONTHS).with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX);
    }

    /**
     * 上季度开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime lastQuarterStartTime() {
        LocalDate now = LocalDate.now();
        Month firstMonthOfQuarter = Month.of(now.getMonth().firstMonthOfQuarter().getValue());
        Month firstMonthOfLastQuarter = firstMonthOfQuarter.minus(3L);
        int yearOfLastQuarter = firstMonthOfQuarter.getValue() < 4 ? now.getYear() - 1 : now.getYear();
        return LocalDateTime.of(LocalDate.of(yearOfLastQuarter, firstMonthOfLastQuarter, 1), LocalTime.MIN);
    }

    /**
     * 上季度结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime lastQuarterEndTime() {
        LocalDate now = LocalDate.now();
        Month firstMonthOfQuarter = Month.of(now.getMonth().firstMonthOfQuarter().getValue());
        Month firstMonthOfLastQuarter = firstMonthOfQuarter.minus(1L);
        int yearOfLastQuarter = firstMonthOfQuarter.getValue() < 4 ? now.getYear() - 1 : now.getYear();
        return LocalDateTime.of(LocalDate.of(yearOfLastQuarter, firstMonthOfLastQuarter, firstMonthOfLastQuarter.maxLength()), LocalTime.MAX);
    }

    /**
     * 上半年开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime lastHalfYearStartTime() {
        LocalDate now = LocalDate.now();
        int lastHalfYear = (now.getMonthValue() > 6) ? now.getYear() : now.getYear() - 1;
        Month firstMonthOfLastHalfYear = (now.getMonthValue() > 6) ? Month.JANUARY : Month.JULY;
        return LocalDateTime.of(LocalDate.of(lastHalfYear, firstMonthOfLastHalfYear, 1), LocalTime.MIN);
    }

    /**
     * 上半年结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime lastHalfYearEndTime() {
        LocalDate now = LocalDate.now();
        int lastHalfYear = (now.getMonthValue() > 6) ? now.getYear() : now.getYear() - 1;
        Month lastMonthOfLastHalfYear = (now.getMonthValue() > 6) ? Month.JUNE : Month.DECEMBER;
        return LocalDateTime.of(LocalDate.of(lastHalfYear, lastMonthOfLastHalfYear, lastMonthOfLastHalfYear.maxLength()), LocalTime.MAX);
    }

    /**
     * 上一年开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime lastYearStartTime() {
        return LocalDateTime.of(LocalDate.now().minus(1L, ChronoUnit.YEARS).with(TemporalAdjusters.firstDayOfYear()), LocalTime.MIN);
    }

    /**
     * 上一年结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime lastYearEndTime() {
        return LocalDateTime.of(LocalDate.now().minus(1L, ChronoUnit.YEARS).with(TemporalAdjusters.lastDayOfYear()), LocalTime.MAX);
    }

    /**
     * 下周开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextWeekStartTime() {
        LocalDate nextWeek = LocalDate.now().plus(1L, ChronoUnit.WEEKS);
        return LocalDateTime.of(nextWeek.minusDays(nextWeek.getDayOfWeek().getValue() - 1), LocalTime.MIN);
    }

    /**
     * 下周结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextWeekEndTime() {
        LocalDate nextWeek = LocalDate.now().plus(1L, ChronoUnit.WEEKS);
        return LocalDateTime.of(nextWeek.plusDays(7 - nextWeek.getDayOfWeek().getValue()), LocalTime.MAX);
    }

    /**
     * 下月开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextMonthStartTime() {
        return LocalDateTime.of(LocalDate.now().plus(1L, ChronoUnit.MONTHS).with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN);
    }

    /**
     * 下月结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextMonthEndTime() {
        return LocalDateTime.of(LocalDate.now().plus(1L, ChronoUnit.MONTHS).with(TemporalAdjusters.lastDayOfMonth()), LocalTime.MAX);
    }

    /**
     * 下季度开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextQuarterStartTime() {
        LocalDate now = LocalDate.now();
        Month firstMonthOfQuarter = Month.of(now.getMonth().firstMonthOfQuarter().getValue());
        Month firstMonthOfNextQuarter = firstMonthOfQuarter.plus(3L);
        int yearOfNextQuarter = firstMonthOfQuarter.getValue() > 9 ? now.getYear() + 1 : now.getYear();
        return LocalDateTime.of(LocalDate.of(yearOfNextQuarter, firstMonthOfNextQuarter, 1), LocalTime.MIN);
    }

    /**
     * 下季度结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextQuarterEndTime() {
        LocalDate now = LocalDate.now();
        Month firstMonthOfQuarter = Month.of(now.getMonth().firstMonthOfQuarter().getValue());
        Month firstMonthOfNextQuarter = firstMonthOfQuarter.plus(5L);
        int yearOfNextQuarter = firstMonthOfQuarter.getValue() > 9 ? now.getYear() + 1 : now.getYear();
        return LocalDateTime.of(LocalDate.of(yearOfNextQuarter, firstMonthOfNextQuarter, firstMonthOfNextQuarter.maxLength()), LocalTime.MAX);
    }

    /**
     * 下半年开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextHalfYearStartTime() {
        LocalDate now = LocalDate.now();
        int nextHalfYear = (now.getMonthValue() > 6) ? now.getYear() + 1 : now.getYear();
        Month firstMonthOfNextHalfYear = (now.getMonthValue() > 6) ? Month.JANUARY : Month.JULY;
        return LocalDateTime.of(LocalDate.of(nextHalfYear, firstMonthOfNextHalfYear, 1), LocalTime.MIN);
    }

    /**
     * 下半年结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextHalfYearEndTime() {
        LocalDate now = LocalDate.now();
        int lastHalfYear = (now.getMonthValue() > 6) ? now.getYear() + 1 : now.getYear();
        Month lastMonthOfNextHalfYear = (now.getMonthValue() > 6) ? Month.JUNE : Month.DECEMBER;
        return LocalDateTime.of(LocalDate.of(lastHalfYear, lastMonthOfNextHalfYear, lastMonthOfNextHalfYear.maxLength()), LocalTime.MAX);
    }

    /**
     * 下一年开始时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextYearStartTime() {
        return LocalDateTime.of(LocalDate.now().plus(1L, ChronoUnit.YEARS).with(TemporalAdjusters.firstDayOfYear()), LocalTime.MIN);
    }

    /**
     * 下一年结束时间
     *
     * @return LocalDateTime
     */
    public static LocalDateTime nextYearEndTime() {
        return LocalDateTime.of(LocalDate.now().plus(1L, ChronoUnit.YEARS).with(TemporalAdjusters.lastDayOfYear()), LocalTime.MAX);
    }
}
